//
//  OosDao.m
//  Oos4ios
//
//  Created by Pablo Gonzalez on 3/17/11.
//

#import <oos4ios/Exceptions/MethodNotImplementedException.h>
#import "../../Macros/LazyPropertyMacro.h"
//#import "OosDao+Internal.h"
#import <oos4ios/DAOs/OosDao.h>
#import "../../Atom/Services/OosAtomService.h"
#import "../../Atom/Queries/OosQuery.h"
#import<oos4ios/Parsers/IOosFeedParser.h>
#import <oos4ios/Parsers/IOosCategoryParser.h>
#import <oos4ios/Parsers/IOosEntryParser.h>
#import "OosAtomServiceCallback.h"
#import "OosJsonService.h"

@interface OosDao (LazyInit)

- (OosOptionsStore *) optionsLazyInit;

@end

@interface OosDao (Internal)

@property (nonatomic, retain, readonly) OosQuery *query;

@property (nonatomic, retain, readonly) OosAtomService *atomService;

@property (nonatomic, retain, readonly) id<IOosFeedParser> feedParser;

@property (nonatomic, retain, readonly) id<IOosCategoryParser> categoryParser;

@property (nonatomic, retain, readonly) id<IOosEntryParser> entryParser;

- (void) notify: (GDataServiceTicketBase *) ticket 
     withObject: (GDataObject *) object 
      withError: (NSError *) error;

@end


@implementation ReadAllCallback

@synthesize readCallback;
@synthesize readSelector;
@synthesize sizeSelector;
@synthesize delegate;
@synthesize dao;

- (void)dealloc
{
    [delegate release];
    [readCallback release];
    [super dealloc];
}

- (void)size:(NSNumber *)totalSize withTicket:(OosDaoTicket *)ticket
{
    if (self.sizeSelector && self.delegate) {
        [delegate performSelector:sizeSelector withObject:totalSize];
    }
}

- (void)readResult:(NSArray *)array 
        withTicket:(OosDaoTicket *)ticket
{
    [ticket.profiler log];
    if (self.delegate && self.readSelector) {
        [self.delegate performSelector:readSelector withObject:array];
    }
    if (self.readCallback) {
        [readCallback readResult:array withTicket:ticket];
    }
    if (self.dao != nil) {
        // get next page
        NSInteger page = [self.dao.options.pageOptions.page integerValue];
        page++;
        self.dao.options.pageOptions.page = [NSNumber numberWithInt:page];
        [self.dao read:self];
    }
}

- (void)resultedInError:(NSError *)error 
             withTicket:(OosDaoTicket *)ticket
{
    [ticket.profiler log];
    if (self.readCallback) {
        [readCallback resultedInError:error withTicket:ticket];
    }
}

@end

@implementation OosDao

@synthesize atomService = mAtomService;

- (OosDaoTicket *) deleteObject:(OosObject *)object 
				   withCallback:(id <IOosDaoDeleteCallback>)daoCallback
{
	if (!self.entryParser) {
        [NSException raise:@"missing entry Parser" 
                    format:@"To Create an object it is needed to have an entry parser"];
    }
    OosDaoTicket *ticket = [OosDaoTicket ticket];
    ticket.sentObject = object;
	OosAtomServiceCallback *callback;
	callback = [OosAtomServiceCallback callback];
	callback.ticket = ticket;
	callback.deleteCallback = daoCallback;
    callback.feedParser = self.feedParser;
    callback.categoryParser = self.categoryParser;
    callback.entryParser = self.entryParser;
	self.atomService.query = self.query;
    OosAtomService *atomService;
    atomService = self.atomService;
    
    OosEntry *entry = [self.entryParser reverseParseEntry:object];
    
	ticket.gdataTicket = [atomService deleteEntry:entry 
                                     withCallback:callback];
	return ticket;
}

- (OosDaoTicket *) update:(OosObject *)object 
			 withCallback:(id <IOosDaoUpdateCallback>)daoCallback
{
	if (!self.entryParser) {
        [NSException raise:@"missing entry Parser" 
                    format:@"To Create an object it is needed to have an entry parser"];
    }
    OosDaoTicket *ticket = [OosDaoTicket ticket];
    ticket.sentObject = object;
	OosAtomServiceCallback *callback;
	callback = [OosAtomServiceCallback callback];
	callback.ticket = ticket;
	callback.updateCallback = daoCallback;
    callback.feedParser = self.feedParser;
    callback.categoryParser = self.categoryParser;
    callback.entryParser = self.entryParser;
	self.atomService.query = self.query;
    OosAtomService *atomService;
    atomService = self.atomService;
    OosEntry *entry = [self.entryParser reverseParseEntry:object];
//    NSLog(@"updating entry: %@", [entry description]);
	ticket.gdataTicket = [atomService update:entry 
                                withCallback:callback];
	return ticket;
}

- (OosDaoTicket *) read:(id <IOosDaoReadCallback>)daoCallback
{
    OosDaoTicket *ticket = [OosDaoTicket ticket];
    //
    ticket.profiler = [TimeProfiler startProfilerWithMessage:
                       [NSString stringWithFormat: @"reading : (%@)", self]];
    //
    if (!atomReadCallback) {
        atomReadCallback = [OosAtomServiceCallback callback];
    }
    atomReadCallback.ticket = ticket;
    atomReadCallback.readCallback = daoCallback;
    atomReadCallback.feedParser = self.feedParser;
    atomReadCallback.categoryParser = self.categoryParser;
    atomReadCallback.entryParser = self.entryParser;
    if ([daoCallback conformsToProtocol:@protocol(IOosDaoSizeCallback)]) {
        atomReadCallback.sizeCallback = (id<IOosDaoSizeCallback>) daoCallback;
    }
    
    self.atomService.query = self.query;
    if (self.options.queryOptions.alt == nil) {
        ticket.gdataTicket = [self.atomService read: atomReadCallback];
    } else {
        OosJsonService *service = [[OosJsonService service] retain];
        service.query = self.query;
        if([NSThread isMainThread]) {
            [service read:atomReadCallback];
        } else {
            NSLog(@"This should be run on the main thread. NSULConnection is on charge of taking it back.");
            [service performSelectorOnMainThread:@selector(read:) withObject:atomReadCallback waitUntilDone:NO];
        }
        [service release];
    }
    
    return ticket;
}

- (void) readWithNotificationName: (NSString *) notificationName
{
    GDataServiceTicketBase *ticket = [self.atomService fetchPublicFeedWithQuery: self.query 
                                                                      feedClass: self.atomService.feedClass 
                                                                       delegate: self didFinishSelector:@selector(notify:withObject:withError:)];
    ticket.userData = notificationName;
}

- (void) notify: (GDataServiceTicketBase *) ticket 
     withObject: (GDataObject *) object 
      withError: (NSError *) error
{
    NSArray *result = [self.feedParser parseFeed: (OosFeed *) object];
    NSMutableArray *resultIds = [NSMutableArray arrayWithCapacity:result.count];
    for (NSManagedObject *managedObject in result) {
        [resultIds addObject: managedObject.objectID];
    }
    [[NSNotificationCenter defaultCenter] postNotificationName: (NSString *)ticket.userData 
                                                        object: resultIds 
                                                      userInfo: nil];
}
                                      

- (void) pageRead: (NSArray *) pageRead
{
    if (pageRead.count > 0) {
        NSInteger page = [self.options.pageOptions.page integerValue];
        page++;
        self.options.pageOptions.page = [NSNumber numberWithInt:page];
        [self read:readAllCallback];
    }
}

- (OosDaoTicket *)readAll:(id<IOosDaoReadCallback>)callback
{
    if (!readAllCallback) {
        readAllCallback = [[[ReadAllCallback alloc] init] retain];
        readAllCallback.dao = self;
    }
    readAllCallback.readCallback = [callback retain];
    return [self read:readAllCallback];
}





-(OosDaoTicket *) create:(OosObject *)object 
			withCallback:(id <IOosDaoCreateCallback>)daoCallback
{
    if (!self.entryParser) {
        [NSException raise:@"missing entry Parser" 
                    format:@"To Create an object it is needed to have an entry parser"];
    }
    OosDaoTicket *ticket = [OosDaoTicket ticket];
    ticket.sentObject = object;
	OosAtomServiceCallback *callback;
	callback = [OosAtomServiceCallback callback];
	callback.ticket = ticket;
	callback.createCallback = daoCallback;
    //callback.feedParser = self.feedParser;
    //callback.categoryParser = self.categoryParser;
    callback.entryParser = self.entryParser;
	self.atomService.query = self.query;
    OosAtomService *atomService;
    atomService = self.atomService;
    
    OosEntry *entry = nil;
    if (object) {
        entry = [self.entryParser reverseParseEntry:object];
    }
    
	ticket.gdataTicket = [atomService create:entry 
           withCallback:callback];
	return ticket;
}

- (int) page
{
	OosOptionsStore *store = [self options];
	NSNumber *number = [[store pageOptions] page];
	return (number) ? [number intValue] : 1;
}

- (int) pageSize
{
	OosOptionsStore *store = [self options];
	NSNumber *number = [[store pageOptions] pageSize];
	return (number) ? [number intValue] : 10;
}

lazyReadOnlySynthesize(OosOptionsStore *, options);

- (OosOptionsStore *) optionsLazyInit
{
	return [OosOptionsStore store];
}

- (OosQuery *) query
{
	[MethodNotImplementedException raiseForSelector:_cmd inObject:self];
	return nil;
}

- (void)initAtomService:(OosAtomService *)atomService
{
    [MethodNotImplementedException raiseForSelector:_cmd inObject:self];
}

- (OosAtomService *) atomService
{
    if (!mAtomService) {
        mAtomService = [[OosAtomService atomService] retain];
        [self initAtomService:mAtomService];
    }
	//[MethodNotImplementedException raiseForSelector:_cmd inObject:self];
	return mAtomService;
}

- (id <IOosFeedParser>) feedParser
{
	return nil;
}

- (id <IOosCategoryParser>) categoryParser
{
	return nil;
}

- (id <IOosEntryParser>) entryParser
{
	return nil;
}

- (void)cancel
{
    
}

- (void)dealloc
{
    [readAllCallback release];
    readAllCallback = nil;
    [mAtomService release];
    [options release];
    [super dealloc];
}

@end
